package com.whs.demo.ui;

import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.utils.DragListener;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.SnapshotArray;

/**
 * 滑动列表
 * 
 * @Description:
 * @author whs
 * @date 2015-11-24 下午3:04:39
 * @version V1.0
 */
public class ScrollList
    extends Group {

    // 滑动动画
    private final Animator animator = new Animator();
    private boolean clip;
    // 截取区域，避免改变Yzhou
    private final Rectangle cullingArea = new Rectangle();
    private final Dragger dragger = new Dragger();
    private final Group list = new Group();
    private final Group cloudlist = new Group();
    private Rectangle scissor;
    private float paddingTop = -100F;
    private float paddingBottom = 100F;

    public ScrollList() {
        clip = true;
        list.setCullingArea(cullingArea);
        super.addActor(list);
        addListener(dragger);
    }


    private Rectangle calculateScissors(Matrix4 matrix4) {
        Rectangle rectangle = Rectangle.tmp;
        rectangle.set(0.0F, 0.0F, getWidth(), getHeight());
        if (scissor == null) {
            scissor = new Rectangle();
        }
        ScissorStack.calculateScissors(getStage().getCamera(), matrix4, rectangle, scissor);
        return scissor;
    }

    // TODO - debug @HTP Smali2JavaUI版本
    private float getLimitedListY(float y) {
        float ret = y;
        float maxListY = getMaxListY();
        if (ret < paddingTop) {
            ret = paddingTop;
        } else if (ret > (maxListY + paddingBottom)) {
            ret = (maxListY + paddingBottom);
        }
        return ret;
    }

    private float getListY() {
        return (list.getY() + list.getHeight()) - getHeight();
    }

    private float getCloudListY() {
        return (cloudlist.getY() + cloudlist.getHeight()) - getHeight();
    }

    public float getMaxListY() {
        return Math.max(0.0F, getListHeight() - getHeight());
    }

    private void setListY(float f) {
        list.setY((f + getHeight()) - list.getHeight());
    }

    public void setPaddingBottom(float paddingBottom) {
        this.paddingBottom = paddingBottom;
    }

    public void setPaddingTop(float paddingTop) {
        this.paddingTop = paddingTop;
    }

    private void setCloudListY(float f) {
        cloudlist.setY(f - 2000);
    }

    public void act(float f) {
        super.act(f);
        animator.update(f);
    }

    public void addActor(Actor actor) {
        list.addActor(actor);
    }

    public void addActorAfter(Actor actor, Actor actor1) {
        list.addActorAfter(actor, actor1);
    }

    public void addActorAt(int i, Actor actor) {
        list.addActorAt(i, actor);
    }

    public void addActorBefore(Actor actor, Actor actor1) {
        list.addActorBefore(actor, actor1);
    }

    public void clear() {
        list.clear();
    }

    /**
     * 这将限制渲染到的矩形“clipBounds”的范围之内
     */
    public void draw(Batch spritebatch, float f) {
        applyTransform(spritebatch, computeTransform());
        cullingArea.set(0.0F, -list.getY(), getWidth(), getHeight());

        if (clip) {
            if (ScissorStack.pushScissors(calculateScissors(spritebatch.getTransformMatrix()))) {
                setTransform(true);
                drawChildren(spritebatch, f);
                spritebatch.flush();
                ScissorStack.popScissors();
            }
        } else {
            setTransform(true);
            drawChildren(spritebatch, f);
        }
        resetTransform(spritebatch);
    }

    public Actor findActor(String s) {
        return list.findActor(s);
    }

    public SnapshotArray<Actor> getChildren() {
        return list.getChildren();
    }

    public float getListHeight() {
        return list.getHeight();
    }

    public float getTapSquareSize() {
        return dragger.getTapSquareSize();
    }

    public Actor hit(float x, float y, boolean flag) {
        if (x >= 0.0F && x < getWidth() && y >= 0.0F && y < getHeight()) {
            return super.hit(x, y, flag);
        } else {
            return null;
        }
    }

    public boolean isClip() {
        return clip;
    }

    public boolean isDragging() {
        return dragger.isDragging();
    }

    public boolean removeActor(Actor actor) {
        return list.removeActor(actor);
    }

    public void setClip(boolean flag) {
        clip = flag;
    }

    public void setHeight(float f) {
        float f1 = getListY();
        super.setHeight(f);
        setListY(f1);
        setCloudListY(getCloudListY());
    }

    public void setListHeight(float f) {
        float f1 = getListY();
        list.setHeight(f);
        cloudlist.setHeight(f + 1500);
        setCloudListY(getCloudListY());
        setListY(f1);
    }

    public void setProgress(float f) {
        setListY(f * getMaxListY());
        setCloudListY(f * getMaxListY());
        animator.reset();
    }

    /**
     * 获取当前进度
     * 
     * @author whs
     * @date 2015-7-10 上午9:45:16
     * @param @return
     * @return float
     * @Description: TODO
     */
    public float getProgress() {
        return getListY() / getMaxListY();
    }

    public void setTapSquareSize(float f) {
        dragger.setTapSquareSize(f);
    }

    public boolean swapActor(int i, int j) {
        return list.swapActor(i, j);
    }

    public boolean swapActor(Actor actor, Actor actor1) {
        return list.swapActor(actor, actor1);
    }

    public void addbackaction(float f) {
        float ret = f;
        float maxListY = getMaxListY();
        if (ret > 0F) {
            list.addAction(Actions.moveTo(0, 0, 0.5f, Interpolation.sineIn));
        } else if (ret < -maxListY) {
            list.addAction(Actions.moveTo(0, -maxListY, 0.5f, Interpolation.sineIn));
        }
    }

    private class Animator {

        private static final float duration = 0.8F;
        private float distance;
        private float start;
        private boolean stopped;
        private float time;

        private Animator() {
        }

        public void begin(float f) {
            stopped = false;
            start = getListY();
            distance = f / 2.5F;
            time = 0.0F;
        }

        public void reset() {
            distance = 0.0F;
        }

        public void resume() {
            stopped = false;
        }

        public void stop() {
            stopped = true;
        }

        public void update(float f) {
            if (!stopped && distance != 0.0F) {
                time = f + time;
                if (time < duration) {
                    float f1 = Interpolation.sineOut.apply(time / duration);
                    float f2 = start + f1 * distance;
                    float f3 = getLimitedListY(f2);
                    if (f2 < 0) {
                        time = time + (Math.abs(f2 / 100));

                    } else if (f2 > 1800) {
                        time = time + (Math.abs(f2 / 1900));
                    } else if (f2 > getListHeight() - 100 - paddingBottom) {
                        time = time + (Math.abs(f2 / getListHeight() + paddingBottom));
                        if (time >= duration) {
                            float f4 = start + distance;
                            float f5 = getLimitedListY(f4);
                            setListY(f5);
                            setCloudListY(f5);
                            addbackaction(list.getY());
                            distance = 0.0F;
                        }

                    } else {

                    }
                    setListY(f3);
                    setCloudListY(f3);
                } else {
                    float f4 = start + distance;
                    float f5 = getLimitedListY(f4);
                    setListY(f5);
                    setCloudListY(f5);
                    addbackaction(list.getY());
                    distance = 0.0F;
                }
            }
        }

    }

    private class Dragger
        extends DragListener {

        private int button;
        private final long deltaTime[];
        private final float deltaY[];
        private int index;
        private float lastStageY;
        private long lastTime;
        private int pointer;
        private float startListY;
        private float startStageY;

        private Dragger() {
            deltaY = new float[8];
            deltaTime = new long[8];
        }

        public void drag(InputEvent inputevent, float f, float f1, int i) {
            float f2 = inputevent.getStageY();
            float f3 = startListY + (f2 - startStageY);
            float f4 = getLimitedListY(f3);
            setListY(f4);
            setCloudListY(f4);
            deltaY[index] = f2 - lastStageY;
            lastStageY = f2;
            long l = System.currentTimeMillis();
            deltaTime[index] = l - lastTime;
            lastTime = l;
            index = (1 + index) % deltaY.length;
        }

        public void dragStart(InputEvent inputevent, float f, float f1, int i) {
            startStageY = inputevent.getStageY();
            startListY = getListY();
            for (int j = 0; j < 8; j++) {
                deltaY[j] = 0.0F;
                deltaTime[j] = 0L;
            }

            index = 0;
            lastStageY = inputevent.getStageY();
            lastTime = System.currentTimeMillis();
        }

        public void dragStop(InputEvent inputevent, float f, float f1, int i) {
            float f2 = 0.0F;
            long l = 0L;
            for (int j = 0; j < deltaY.length; j++) {
                f2 += deltaY[j];
                l += deltaTime[j];
            }

            float f3;
            if (l == 0L) {
                f3 = 0.0F;
            } else {
                f3 = f2 / ((float) l / 1000F);
            }
            animator.begin(f3);
        }

        public boolean touchDown(InputEvent inputevent, float f, float f1, int i, int j) {
            if (super.touchDown(inputevent, f, f1, i, j)) {
                animator.stop();
                pointer = i;
                button = j;
                return true;
            } else {
                return false;
            }
        }

        public void touchUp(InputEvent inputevent, float f, float f1, int i, int j) {
            super.touchUp(inputevent, f, f1, i, j);
            if (pointer == i && button == j) {
                animator.resume();
                pointer = -1;
                button = -1;
            }

        }

    }

}
